<template>
  <div
    ref="editWrapper"
    class="edit-wrapper"
    :style="styles"
    :data-component-id="id"
    :class="{ active: active, hidden: hidden }"
    @click="onItemClick(id)"
    @mousedown="startMove"
  >
    <slot></slot>
    <div class="resizes">
      <div class="resizer top-left" @mousedown.stop="startResize('top-left')"></div>
      <div class="resizer top-right" @mousedown.stop="startResize('top-right')"></div>
      <div class="resizer bottom-left" @mousedown.stop="startResize('bottom-left')"></div>
      <div class="resizer bottom-right" @mousedown.stop="startResize('bottom-right')"></div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { pick } from 'lodash-es'

type ResizeDirection = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'

const props = withDefaults(
  defineProps<{
    id: string
    active?: boolean
    hidden?: boolean
    props?: { [key: string]: any }
  }>(),
  { active: false }
)

const emits = defineEmits<{
  (event: 'setActive', id: string): void
  (event: 'updatePosition', data: any): void
}>()

const editWrapper = ref<null | HTMLElement>(null)
const styles = computed(() => pick(props.props, ['position', 'top', 'left', 'width', 'height']))

let container: HTMLElement = null
let isMoving = false

const gap = {
  x: 0,
  y: 0
}

const onItemClick = (id: string) => {
  emits('setActive', id)
}

const calculateMovePosition = (e: MouseEvent, currentRect: DOMRect, container: HTMLElement) => {
  const containerRect = container.getBoundingClientRect()
  let left = e.clientX - gap.x - containerRect.left
  let top = e.clientY - gap.y - containerRect.top + container.scrollTop // 加上向上滚动的距离

  let maxLeft = containerRect.width - currentRect.width
  let maxTop = containerRect.height - currentRect.height
  // if (props.active) {
  //   maxTop -= 4
  // }

  if (left < 0) {
    left = 0
  }
  if (top < 0) {
    top = 0
  }
  if (left > maxLeft) {
    left = maxLeft
  }
  if (top > maxTop) {
    top = maxTop
  }

  return { left, top }
}

const calculateMoveResizer = (
  e: MouseEvent,
  direction: ResizeDirection,
  currentRect: DOMRect,
  container: HTMLElement
) => {
  const containerRect = container.getBoundingClientRect()
  const { clientX, clientY } = e
  const { left, right, top, bottom } = currentRect

  const rightWidth = clientX - left
  const leftWidth = right - clientX
  const bottomHeight = clientY - top
  const topHeight = bottom - clientY
  let topOffset = clientY - containerRect.top + container.scrollTop // 加上向上滚动的距离
  let leftOffset = clientX - containerRect.left

  switch (direction) {
    case 'top-left':
      return {
        width: leftWidth,
        height: topHeight,
        top: topOffset,
        left: leftOffset
      }
    case 'top-right':
      return {
        width: rightWidth,
        height: topHeight,
        top: topOffset
      }
    case 'bottom-left':
      return {
        width: leftWidth,
        height: bottomHeight,
        left: leftOffset
      }
    case 'bottom-right':
      return {
        width: rightWidth,
        height: bottomHeight
      }
    default:
      break
  }
}

const startResize = (direction: ResizeDirection) => {
  container = document.getElementById('canvas-ares') as HTMLElement
  const currentElement = editWrapper.value
  if (!container || !currentElement) return
  const currentRect = currentElement.getBoundingClientRect()

  const handleMove = (e: MouseEvent) => {
    const size = calculateMoveResizer(e, direction, currentRect, container)
    if (size) {
      const style = currentElement.style
      style.width = size.width + 'px'
      style.height = size.height + 'px'
      if (size.left) {
        style.left = size.left + 'px'
      }
      if (size.top) {
        style.top = size.top + 'px'
      }
    }
  }

  const handleMoveUp = (e: MouseEvent) => {
    document.removeEventListener('mousemove', handleMove)
    const size = calculateMoveResizer(e, direction, currentRect, container)
    emits('updatePosition', { ...size, id: props.id })
    nextTick(() => {
      document.removeEventListener('mouseup', handleMoveUp)
    })
  }

  document.addEventListener('mousemove', handleMove)
  document.addEventListener('mouseup', handleMoveUp)
}

const startMove = (e: MouseEvent) => {
  // console.log('startMove', e)
  container = document.getElementById('canvas-ares') as HTMLElement
  const currentElement = editWrapper.value
  if (!container || !currentElement) return
  const currentRect = currentElement.getBoundingClientRect()
  // clientX: 点击位置距离当前body可视区域的x坐标； pageX: clientX + 有滚动条时的距离
  // 计算鼠标点击时相对于当前容器的 x, y
  gap.x = e.clientX - currentRect.left
  gap.y = e.clientY - currentRect.top
  // console.log('startMove', gap)

  const handleMove = (e: MouseEvent) => {
    e.preventDefault()
    const { left, top } = calculateMovePosition(e, currentRect, container)
    isMoving = true
    // console.log('handleMove', left, top)
    currentElement.style.left = left + 'px'
    currentElement.style.top = top + 'px'
  }

  const handleMoveUp = (e: MouseEvent) => {
    document.removeEventListener('mousemove', handleMove)
    if (isMoving) {
      const { left, top } = calculateMovePosition(e, currentRect, container)
      // console.log('handleMoveUp', left, top)
      emits('updatePosition', { left, top, id: props.id })
      isMoving = false
    }
    nextTick(() => {
      document.removeEventListener('mouseup', handleMoveUp)
    })
  }

  document.addEventListener('mousemove', handleMove)
  document.addEventListener('mouseup', handleMoveUp)
}
</script>
<style lang="scss" scoped>
.edit-wrapper {
  padding: 0px;
  cursor: pointer;
  border: 1px solid transparent;
  user-select: none; // 用户在页面上不能选中文本
  box-sizing: content-box !important; // border-box 的 width 包括 padding 和 border; content-box 则不会

  // & > * {
  //   position: static !important;
  //   width: 100% !important;
  //   height: 100% !important;
  // }

  &:hover {
    border: 1px dashed #ccc;
  }

  &.hidden {
    display: none;
  }

  &.active {
    border: 1px solid #1890ff;
    user-select: none;
    z-index: 1500;
    .resizes {
      display: block;
    }
  }

  .resizes {
    display: none;

    .resizer {
      width: 8px;
      height: 8px;
      border-radius: 50%;
      background: #fff;
      border: 1px solid #1890ff;
      position: absolute;

      &.top-left {
        left: -4px;
        top: -4px;
        cursor: nwse-resize;
      }

      &.top-right {
        right: -4px;
        top: -4px;
        cursor: nesw-resize;
      }

      &.bottom-left {
        left: -4px;
        bottom: -4px;
        cursor: nesw-resize;
      }

      &.bottom-right {
        right: -4px;
        bottom: -4px;
        cursor: nwse-resize;
      }
    }
  }
}
</style>
